package ro.myApp.security.service.role;

import java.util.LinkedList;
import java.util.List;

import javax.ejb.EJB;
import javax.ejb.Local;
import javax.ejb.Remote;
import javax.ejb.Stateless;

import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Restrictions;

import ro.myApp.commons.dto.BaseDtoMessage;
import ro.myApp.commons.service.exceptions.ErrorKeys;
import ro.myApp.commons.service.exceptions.ViewException;
import ro.myApp.commons.tree.TreeStructureCompositTransformer;
import ro.myApp.esb.service.MessageBasedService;
import ro.myApp.esb.service.MessageBasedServiceImpl;
import ro.myApp.security.dto.RoleCreateMessage;
import ro.myApp.security.dto.RoleFindAllFiltered;
import ro.myApp.security.dto.RoleFindUniqueFiltered;
import ro.myApp.security.dto.RoleSaveMessage;
import ro.myApp.security.dto.RolesFindAllHierarchyMessage;
import ro.myApp.security.entities.Role;

@Local(value=MessageBasedService.class)
@Remote(value=MessageBasedService.class)
@Stateless
public class RolesManagementServiceImpl extends MessageBasedServiceImpl{

	@EJB(mappedName="RoleActionServiceImpl/local")
	private RoleActionService roleActionService; 

	@EJB(mappedName="RoleAccessServiceImpl/local")
	private RoleAccessService roleAccessService; 
	
	@Override
	protected Object execute(BaseDtoMessage dto) throws Throwable {
		if (dto instanceof RolesFindAllHierarchyMessage)
			return filterRolesHierarchy((RolesFindAllHierarchyMessage) dto);
		else if (dto instanceof RoleSaveMessage)
			return saveRole(((RoleSaveMessage)dto).getRole());
		else if (dto instanceof RoleCreateMessage)
			return createRole((RoleCreateMessage)dto);
		else if (dto instanceof RoleFindUniqueFiltered)
			return findRole ((RoleFindUniqueFiltered)dto);
		else if (dto instanceof RoleFindAllFiltered)
			return findRole ((RoleFindAllFiltered)dto);
		throw new IllegalArgumentException(
			"This message type is currently not supported");
	}

	private Object findRole(RoleFindAllFiltered dto) {
		List<Criterion> crit = new LinkedList<Criterion>();
		crit.add(Restrictions.eq("deleted", Boolean.FALSE));
		return roleAccessService.findFiltered(crit.toArray(new Criterion[]{}));
	}

	private Object findRole(RoleFindUniqueFiltered dto) {
		List<Criterion> crit = new LinkedList<Criterion>();
		if (null != dto.getId())
			crit.add(Restrictions.idEq(dto.getId()));
		crit.add(Restrictions.eq("deleted", Boolean.FALSE));
		return roleAccessService.findUniqueFiltered(crit.toArray(new Criterion[]{}));
	}

	private Object createRole (RoleCreateMessage dto){
		Role role = new Role();
		role.setBaseRole(dto.getBaseRole());
		role.setCode(dto.getBaseRole().getText());
		role.setDescription("base role for "+dto.getBaseRole().getText());
		role.setLabel(dto.getBaseRole().getText());
		
		role.setLeaf(true);
		role.setRoot(false);
		
		role.setLevel(dto.getParent().getLevel()+1);
		role.setOrder(dto.getParent().getChildren().size()+1);
		role.setPath(dto.getParent().getPath()+"."+role.getOrder());
		
		role.setParent(dto.getParent());
		dto.getParent().getChildren().add(role);
		return role;
	}
	
	private Object saveRole(Role role) {
		 int countByLabel = roleAccessService.countFiltered(
					Restrictions.eq("label", role.getLabel()));
		 if (countByLabel>0)
				throw new ViewException(ErrorKeys.DUPLICATE_ROLENAME);
		 
		 int countByCode = roleAccessService.countFiltered(
					Restrictions.eq("code", role.getCode()));
		 if (countByCode>0)
				throw new ViewException(ErrorKeys.DUPLICATE_ROLECODE);
		 return roleActionService.updateEntity(role);
		 
	}

	private List<Role> filterRolesHierarchy(RolesFindAllHierarchyMessage dto) {
		List<Criterion> crit = new LinkedList<Criterion>();
		crit.add(Restrictions.eq("deleted", Boolean.FALSE));
		crit.add(Restrictions.eq("root", Boolean.TRUE));
		List<Role> roots = roleAccessService.findFiltered(crit.toArray(new Criterion[]{}));
		
		List<Role> result = new LinkedList<Role>();
		
		for (Role root : roots) {
			List<Criterion> crit2 = new LinkedList<Criterion>();
			crit2.add(Restrictions.eq("deleted", Boolean.FALSE));
			crit2.add(Restrictions.or(
					Restrictions.like("path", root.getPath()+".%"),
					Restrictions.eq("path", root.getPath())));
			List<Role> children = roleAccessService.findFiltered(crit2.toArray(new Criterion[]{}));
			result.add(TreeStructureCompositTransformer.getInstance().transformToTreeStructure(children));
		}
		return result;
	}
	
}
